package userInterface;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.io.File;
import java.util.ArrayList;

import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import networkInterface.Utilisateur;
import protocol.FileNotify;
import controller.ChatController;
import controller.Refreshable;

/**
 * Classe de l'interface graphique.
 * 
 * @author Flo
 * 
 */
public class ChatGui extends JFrame implements WindowListener, Refreshable {
	/**
	 * La superclasse {@link Component} est serialisable... pour faire plaisir
	 * au warning, on ajoute un ID.
	 */
	private static final long serialVersionUID = 1L;

	/**
	 * Bouton sur lequel on va cliquer pour envoyer du texte
	 */
	private JButton btnSend;
	/**
	 * Liste des personnes connectees sur laquelle on peut cliquer pour choisir
	 * un destinataire
	 */
	private JList listeCopains;
	/**
	 * Zone de texte ou les discussions, notifications de fichier, connexion ou
	 * deconnexions seront ecrites
	 */
	private JTextArea discussion;
	/**
	 * Zone ou l'utilisateur entre son pseudo avant de se connecter
	 */
	private JTextArea pseudo;
	/**
	 * Bouton sur lequel on clique pour se connecter, se changer en bouton
	 * "deconnecter" quand on est connecte
	 */
	private JButton btnConnect;
	/**
	 * Zone de texte dans laquelle on ecrit un message a envoyer
	 */
	private JTextArea msgToSend;
	/**
	 * ChatController
	 */
	private ChatController chat;
	/**
	 * Booleen connecte ou non
	 */
	private boolean connected;
	/**
	 * Zone dans laquelle est mise la discussion pour qu'il y ait une scrollbar
	 */
	private JScrollPane scrollPane;
	/**
	 * Bouton pour envoyer un fichier a quelqu'un (et le choisir)
	 */
	private JButton btnFile;
	/**
	 * Accepter la reception d'un fichier
	 */
	private JButton btnAcceptFile;
	/**
	 * Annuler la reception d'un fichier
	 */
	private JButton btnCancelFile;

	/**
	 * Constructeur, initialise la fenetre
	 */
	public ChatGui() {
		setResizable(false);
		setPreferredSize(new Dimension(930, 590));
		setTitle("ChatSystem");
		this.connected = false;
		initComponents();
		this.chat = new ChatController(this);
	}

	/**
	 * initialise les elements de la fenetre
	 */
	private void initComponents() {
		getContentPane().setLayout(null);

		// ********************************************************************
		// Bouton envoyer
		// ********************************************************************

		btnSend = new JButton("Send");
		// Pour commencer le bouton est grise
		btnSend.setEnabled(false);
		btnSend.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				// Si aucun texte n'est ecrit dans le champ de saisie, on
				// n'envoie pas de message
				String texte = msgToSend.getText();
				if (texte == null | texte.equals("")) {
					return;
				}
				// Envoi du message
				if (chat.envoyerTexte(texte)) {
					// On vide le champ de saisie
					msgToSend.setText(null);
				} else {
					discussion.setText(discussion.getText()
							+ "\t >> Il faut choisir un copain ! <<\n");
				}
			}
		});
		btnSend.setBounds(815, 518, 99, 23);
		getContentPane().add(btnSend);

		// ********************************************************************
		// Liste des contacts
		// ********************************************************************

		DefaultListModel dlm = new DefaultListModel();
		listeCopains = new JList(dlm);
		listeCopains.addListSelectionListener(new ListSelectionListener() {
			public void valueChanged(ListSelectionEvent arg0) {
				if (arg0 != null) {
					JList liste = (JList) arg0.getSource();
					String nomCopain = (String) liste.getSelectedValue();
					System.out.println("dans le listener de liste, nom = "
							+ nomCopain);
					chat.choisirCopainCourant(nomCopain);
				}
			}
		});

		listeCopains.setBounds(10, 11, 135, 495);
		// On la grise pour commencer
		listeCopains.setEnabled(false);
		getContentPane().add(listeCopains);

		// ********************************************************************
		// Champ du nom d'utilisateur
		// ********************************************************************

		pseudo = new JTextArea();
		pseudo.setBounds(815, 11, 89, 23);
		// On pourra ecrire dedans
		pseudo.setEditable(true);
		// Pour commencer c'est degrise
		pseudo.setEnabled(true);
		getContentPane().add(pseudo);

		// ********************************************************************
		// Bouton connecter
		// ********************************************************************

		btnConnect = new JButton("Connect");
		btnConnect.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				if (!ChatGui.this.connected) {
					String texte = pseudo.getText();
					// Si aucun pseudo n'est entre, on ne fait rien
					if (texte == null || texte.equals("")) {
						// Avertissement : saisir un pseudo avant de
						// tenter de se connecter
						discussion.setText(discussion.getText()
								+ "\t >> Il faut choisir un pseudo avant de se connecter ! <<\n");
						return;
					}
					// Init du controleur avec le nom et le port
					chat.init(pseudo.getText(), 2235, new MonWriter(discussion));
					// Connexion
					chat.connecter();
					// Le bouton send est degrise
					btnSend.setEnabled(true);
                                        btnFile.setEnabled(true);
					listeCopains.setEnabled(true);
					discussion.setEnabled(true);
					msgToSend.setEnabled(true);
					// On interdit la modification de pseudo quand on est
					// connecte
					pseudo.setEnabled(false);
					// Le bouton change de nom
					btnConnect.setText("Disconnect");
					ChatGui.this.connected = true;
				} else {
					// Deconnexion
					chat.deconnecter();
					// Le bouton send est grise
					btnSend.setEnabled(false);
                                        btnFile.setEnabled(false);
                                        btnAcceptFile.setEnabled(false);
                                        btnCancelFile.setEnabled(false);
					listeCopains.setEnabled(false);
					discussion.setEnabled(false);
					msgToSend.setEnabled(false);
					// On redonne le droit de changer le pseudo
					pseudo.setEnabled(true);
					// Le bouton change de nom
					btnConnect.setText("Connect");
					ChatGui.this.connected = false;
				}
			}
		});
		btnConnect.setBounds(815, 50, 99, 23);
		getContentPane().add(btnConnect);

		// ********************************************************************
		// Zone de texte a envoyer
		// ********************************************************************

		msgToSend = new JTextArea();
		msgToSend.setEditable(true);
		msgToSend.setEnabled(false);
		msgToSend.setBounds(10, 517, 795, 24);
		getContentPane().add(msgToSend);

		// ********************************************************************
		// Zone de conversation
		// ********************************************************************

		scrollPane = new JScrollPane();
		scrollPane.setBounds(155, 11, 650, 495);
		getContentPane().add(scrollPane);

		discussion = new JTextArea();
		scrollPane.setViewportView(discussion);
		// On ne pourra pas ecrire dedans
		discussion.setEditable(false);
		// Et en plus on ne grise pour commencer
		discussion.setEnabled(false);

		// ********************************************************************
		// Bouton d'envoi de fichier
		// ********************************************************************

		btnFile = new JButton("Send File");
		btnFile.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				// Si pas de copain courant, on arrete
				if (chat.getCopainCourant() == null) {
					discussion.setText(discussion.getText()
							+ "\t >> Il faut choisir un copain ! <<\n");
					return;
				}
				// Creation du chooser de fichiers
				JFileChooser chooser = new JFileChooser();
				chooser.setDialogTitle("Choisir le fichier à envoyer...");
				chooser.setDialogType(JFileChooser.OPEN_DIALOG);
				// Affichage et recuperation de la sortie
				int retour = chooser.showOpenDialog(ChatGui.this);
				if (retour == JFileChooser.APPROVE_OPTION) {
					// selection du fichier
					File file = chooser.getSelectedFile();
					// envoyer le fichier au copain choisi
					ChatGui.this.chat.envoyerFileNotify(file);
				}
			}
		});
		btnFile.setBounds(815, 149, 99, 23);
                btnFile.setEnabled(false);
		getContentPane().add(btnFile);

		// ********************************************************************
		// Bouton accepter un fichier
		// ********************************************************************

		btnAcceptFile = new JButton("Accept File");
		btnAcceptFile.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				// Recuperation du premier fichier en attente
				ArrayList<FileNotify> listeFichiers = ChatGui.this.chat
						.getFilesEnAttente();
				FileNotify notify = listeFichiers.remove(0);
				String nomFichier = notify.getNomFichier();
				System.out.println("Path fichier : " + nomFichier);
				// Creation d'un chooser de fichiers, pour sauver
				JFileChooser chooser = new JFileChooser();
				// Construction d'un path par defaut pour le fichier : c'est le
				// repertoire par defaut, plus le nom du fichier
				File currentDir = chooser.getCurrentDirectory();
				String pathFichierDefaut = currentDir + File.separator
						+ nomFichier;
				System.out
						.println("path fichier defaut : " + pathFichierDefaut);
				chooser.setSelectedFile(new File(pathFichierDefaut));
				chooser.setDialogTitle("Sauver le fichier...");
				chooser.setDialogType(JFileChooser.SAVE_DIALOG);
				int retour = chooser.showSaveDialog(ChatGui.this);
				if (retour == JFileChooser.APPROVE_OPTION) {
					// selection du fichier
					File file = chooser.getSelectedFile();
					// envoyer l'ack au copain
					ChatGui.this.chat.envoyerAck(notify.getSourceAddress(),
							true, file);
				} else {
					// Si on clique sur annuler lors du choix du lieu de
					// sauvegarde,
					// on prend ça pour un refus
					ChatGui.this.chat.envoyerAck(notify.getSourceAddress(),
							false, null);
				}

			}
		});
		btnAcceptFile.setBounds(815, 211, 99, 23);
		btnAcceptFile.setEnabled(false);
		getContentPane().add(btnAcceptFile);

		// ********************************************************************
		// Bouton refuser un fichier
		// ********************************************************************

		btnCancelFile = new JButton("Cancel File");
		btnCancelFile.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				ArrayList<FileNotify> listeFichiers = ChatGui.this.chat
						.getFilesEnAttente();
				FileNotify notify = listeFichiers.remove(0);
				ChatGui.this.chat.envoyerAck(notify.getSourceAddress(), false,
						null);
			}
		});
		btnCancelFile.setBounds(815, 245, 99, 23);
		btnCancelFile.setEnabled(false);
		getContentPane().add(btnCancelFile);
		this.pack();
		this.setVisible(true);

		this.addWindowListener(this);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void windowActivated(WindowEvent e) {
		// Inutilise
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void windowClosed(WindowEvent e) {
		// Inutilise
	}

	/**
	 * Seule methode utile de l'interface {@link WindowListener} dans le cas
	 * present. L'application meurt quand on ferme la fenetre.
	 */
	@Override
	public void windowClosing(WindowEvent e) {
		System.exit(EXIT_ON_CLOSE);

	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void windowDeactivated(WindowEvent e) {
		// Inutilise
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void windowDeiconified(WindowEvent e) {
		// Inutilise
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void windowIconified(WindowEvent e) {
		// Inutilise
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void windowOpened(WindowEvent e) {
		// Inutilise
	}

	/**
	 * Methode permettant de rafraichir l'ihm. Elle met a jour la liste de
	 * copains, et si un fichier est en attente de reception, elle rend
	 * disponibles les boutons pour accepter ou refuser le fichier.
	 */
	@Override
	public void refresh() {
		// Mise a jour de la liste des copains
		// Pour commencer, on la vide
		((DefaultListModel) this.listeCopains.getModel()).clear();
		// On recupere la liste de copains du controleur
		ArrayList<Utilisateur> groupeCopains = this.chat.getCopains();
		// Pour chaque copain dans la liste :
		for (Utilisateur copain : groupeCopains) {
			// On l'ajoute a l'ihm
			((DefaultListModel) this.listeCopains.getModel()).addElement(copain
					.getNom());
		}

		// Recuperation de la liste des fichiers en attente
		ArrayList<FileNotify> fichiersARecevoir = this.chat.getFilesEnAttente();
		// Si la liste est vide, on grise les boutons accepter et refuser
		if (fichiersARecevoir.isEmpty()) {
			btnCancelFile.setEnabled(false);
			btnAcceptFile.setEnabled(false);
		} else {
			// Sinon on les rend disponibles
			btnCancelFile.setEnabled(true);
			btnAcceptFile.setEnabled(true);
		}
	}
}
